package com.tzbank.voice.utils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.dc.eai.data.Array;
import com.dc.eai.data.AtomData;
import com.dc.eai.data.CompositeData;
import com.dc.eai.data.Field;
import com.dc.eai.data.FieldAttr;
import com.dc.eai.data.FieldType;

/**
 * Esb报文转换工具类
 * 
 * @author zzj
 * @since 2017-11-16
 * @version 1.0
 */
public class EsbConversionUtil {

	public static final FieldType stringType = FieldType.getEnum("string"); // Esb的String类型
	public static final FieldType doubleType = FieldType.getEnum("double"); // Esb的double类型
	// static int flag = 0;
	private static final String module = EsbConversionUtil.class.getName();

	/**
	 * 报文转换：java.util.Map转换为CompositeData
	 * 
	 * @param context
	 * @return
	 * @throws Exception
	 */
	public static CompositeData mapToCompositeData(Map<String, Object> context) {
		return conversion(context);
	}

	/**
	 * 报文转换：CompositeData转换为java.util.Map
	 * 
	 * @param req_data
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Object> compositeDataToMap(CompositeData req_data) {
		Map<String, Object> input = new HashMap<String, Object>();
		iteratorData(req_data, input);
		return input;
	}

	/**
	 * java.util.Map转换为CompositeData的具体实现
	 * 
	 * @param context
	 * @return
	 * @throws Exception
	 */
	private static CompositeData conversion(Map<String, Object> context) {
		CompositeData resp_data = new CompositeData(); // Esb响应报文
		CompositeData BODY = new CompositeData(); // Esb报文体
		// uisftech:wsf定义服务返回标识，0-成功，1-失败
		int flag = 0;
		// 遍历Map 根据不同的value类型，做相应的操作
		Set<String> contextKeys = context.keySet();
		for (String contextKey : contextKeys) {
			String key = contextKey;
			if (null == key) {
				continue;
			}
			if (!Character.isUpperCase((contextKey.toCharArray())[0])) {
				key = sendConverse(contextKey);
			}
			Object value = context.get(contextKey);
			if (contextKey.equals("sysHead")) {
				flag = conversion(key, value, resp_data);
				continue;
			}
			if (contextKey.equals("appHead")) {
				flag = conversion(key, value, resp_data);
				continue;
			}
			if (contextKey.equals("localHead")) {
				flag = conversion(key, value, resp_data);
				continue;
			}
			flag = conversion(key, value, BODY);
			//判断body转换的结果，如果flag=1，报错，退出循环
			if(flag == 1) {
				break;
			}
		}
		resp_data.addStruct("BODY", BODY);
		if (flag == 1) {
			return returnError("900005", "数据类型错误!!! Esb只支持array、struct、string、double类型.");
		}
		return resp_data;
	}

	/**
	 * BODY里的报文组装
	 * 
	 * @param context
	 * @param value
	 * @param data
	 * @return
	 * @throws Exception
	 */
	private static int conversion(String key, Object value, CompositeData data) {
		int flag = 0;
		// 按照类型组装参数
		if (value != null && flag == 0) {
			if (value instanceof String) {
				FieldAttr fieldAttr = new FieldAttr(stringType, ((String) value).length(), 0);
				Field field = new Field(fieldAttr);
				field.setValue((String) value);
				data.addField(key, field);
			} else if (value instanceof BigDecimal) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 7);
				Field field = new Field(fieldAttr);
				field.setValue(Double.valueOf(value.toString()));
				data.addField(key, field);
			} else if (value instanceof Double) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 7);
				Field field = new Field(fieldAttr);
				field.setValue((Double) value);
				data.addField(key, field);
			} else if (value instanceof Integer) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 0);
				Field field = new Field(fieldAttr);
				field.setValue(Double.valueOf(String.valueOf(value)));
				data.addField(key, field);
			} else if (value instanceof List) {
				Array array = new Array();
				flag = assembleData(value, array);
				if(flag == 1) {
					return flag;
				}
				data.addArray(key, array);
			} else if (value instanceof Map) {
				CompositeData map = new CompositeData();
				flag = assembleData(value, map);
				if(flag == 1) {
					return flag;
				}
				data.addStruct(key, map);
			} else {
				String objectType = value.getClass().getTypeName();
				flag = 1;
				return flag;
			}
		}
		return flag;
	}

	/**
	 * 对List下的子项进行类型分类以及后续处理
	 * 
	 * @param obj
	 * @param parentArray
	 * @throws Exception
	 */
	private static int assembleData(Object obj, Array parentArray) {
		@SuppressWarnings("rawtypes")
		List list = (List) obj;
		int flag = 0;
		for (int i = 0; i < list.size(); i++) {
			Object object = list.get(i);
			if (object == null) {
				continue;
			}
			if (object instanceof String) {
				FieldAttr fieldAttr = new FieldAttr(stringType, ((String) object).length(), 0);
				Field field = new Field(fieldAttr);
				field.setValue((String) object);
				parentArray.addField(i, field);
			} else if (object instanceof BigDecimal) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 7);
				Field field = new Field(fieldAttr);
				field.setValue(Double.valueOf(object.toString()));
				parentArray.addField(i, field);
				// uisftech:wsf增加bigdecimal通过json转报文丢精度
			} else if (object instanceof Integer) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 0);
				Field field = new Field(fieldAttr);
				field.setValue(Double.valueOf(object.toString()));
				parentArray.addField(i, field);
			} else if (object instanceof Double) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 7);
				Field field = new Field(fieldAttr);
				field.setValue((Double) object);
				parentArray.addField(i, field);
			} else if (object instanceof List) {
				Array sonArray = new Array();
				flag = assembleData(object, sonArray);
				if(flag == 1) {
					return flag;
				}
				parentArray.addArray(i, sonArray);
			} else if (object instanceof Map) {
				CompositeData map = new CompositeData();
				flag = assembleData(object, map);
				if(flag == 1) {
					return flag;
				}
				parentArray.addStruct(i, map);
			} else {
				String objectType = object.getClass().getTypeName();
				return flag = 1;
			}
		}
		return flag;
	}

	/**
	 * 对Map的子项进行类型分类以及后续处理
	 * 
	 * @param obj
	 * @param parentMap
	 * @throws Exception
	 */
	private static int assembleData(Object obj, CompositeData parentMap) {
		@SuppressWarnings("rawtypes")
		Map map = (Map) obj;
		// uisftech:wsf定义类型转换返回值,0默认成功，1为失败
		int flag = 0;
		@SuppressWarnings("unchecked")
		Set<String> keySet = map.keySet();
		for (String keys : keySet) {
			String key = sendConverse(keys);
			Object object = map.get(keys);
			if (object == null) {
				continue;
			}
			if (object instanceof String) {
				FieldAttr fieldAttr = new FieldAttr(stringType, ((String) object).length(), 0);
				Field field = new Field(fieldAttr);
				field.setValue((String) object);
				parentMap.addField(key, field);
			} else if (object instanceof BigDecimal) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 7);
				Field field = new Field(fieldAttr);
				field.setValue(Double.valueOf(object.toString()));
				parentMap.addField(key, field);
				// uisftech:wsf增加bigdecimal通过json转报文丢精度
			} else if (object instanceof Integer) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 0);
				Field field = new Field(fieldAttr);
				field.setValue(Double.valueOf(object.toString()));
				parentMap.addField(key, field);
			} else if (object instanceof Double) {
				FieldAttr fieldAttr = new FieldAttr(doubleType, 25, 7);
				Field field = new Field(fieldAttr);
				field.setValue((Double) object);
				parentMap.addField(key, field);
			} else if (object instanceof List) {
				Array sonArray = new Array();
				flag = assembleData(object, sonArray);
				if(flag == 1) {
					return flag;
				}
				parentMap.addArray(key, sonArray);
			} else if (object instanceof Map) {
				CompositeData sonMap = new CompositeData();
				flag = assembleData(object, sonMap);
				parentMap.addStruct(key, sonMap);
				if(flag == 1) {
					return flag;
				}
			} else {
				String objectType = object.getClass().getTypeName();
				return flag = 1;
			}
		}
		return flag;
	}

	/**
	 * 遍历CompositeData，递归获取所有field存进Map（input）
	 * 
	 * @param parent
	 * @param input
	 * @throws Exception
	 */
	private static void iteratorData(CompositeData parent, Map<String, Object> input) {
		@SuppressWarnings("rawtypes")
		Iterator iterator = parent.iterator();
		Map<String, Object> headMap = new HashMap<String, Object>();
		while (iterator.hasNext()) {
			String son = (String) iterator.next();
			AtomData sonData = parent.getObject(son);
			if (sonData.isField()) {
				Field field = parent.getField(son);
				if (field.getFieldType() == doubleType) {
					input.put(recConverse(son), (Double) field.getValue());
				} else {
					input.put(recConverse(son), ((String) field.getValue()).trim());
				}
			} else if (sonData.isStruct()) {
				if (son.equals("SYS_HEAD") | son.equals("APP_HEAD") | son.equals("LOCAL_HEAD")) {
					CompositeData struct = parent.getStruct(son);
					iteratorData(struct, headMap);
					input.put("head", headMap);
					continue;
				}
				if (son.equals("BODY")) {
					CompositeData struct = parent.getStruct(son);
					iteratorData(struct, input);
					continue;
				}
				CompositeData struct = parent.getStruct(son);
				Map<String, Object> map = new HashMap<String, Object>();
				iteratorData(struct, map);
				input.put(recConverse(son), map);
			} else if (sonData.isArray()) {
				Array array = parent.getArray(son);
				List<Object> arrayList = new ArrayList<Object>();
				for (int i = 0; i < array.size(); i++) {
					Map<String, Object> arrayMap = new HashMap<String, Object>();
					CompositeData struct = array.getStruct(i);
					if (son.equals("PAY_ITEM_PROD_ARRAY") || son.equals("ORDER_ITEM_PROD_ARRAY")) {
						iterator(struct, arrayMap);
						arrayList.add(arrayMap);
					} else {
						iteratorData(struct, arrayMap);
						arrayList.add(arrayMap);
					}
				}
				input.put(recConverse(son), arrayList);
			}
		}
	}

	private static void iterator(CompositeData parent, Map<String, Object> input) {
		Field key = parent.getField("PROP_NAME");
		Field value = parent.getField("KEY_VALUE");
		if (key == null) {
			return;
		}
		if (value == null) {
			input.put(recConverse((String) key.getValue()), "");
		} else {
			input.put(recConverse((String) key.getValue()), value.getValue());
		}
	}

	/**
	 * 字段大写转小写
	 * 
	 * @param str
	 * @return
	 */
	private static String recConverse(String str) {
		if (str.contains("_")) {
			String[] strs = str.split("\\_");
			StringBuilder result = new StringBuilder("");
			for (int i = 0; i < strs.length; i++) {
				String words = strs[i].toLowerCase();
				if (i == 0) {
					result.append(words);
				} else {
					char[] cs = words.toCharArray();
					cs[0] -= 32;
					result.append(String.valueOf(cs));
				}
			}
			return result.toString();
		}
		return str.toLowerCase();
	}

	/**
	 * 字段小写转大写
	 * 
	 * @param str
	 * @return
	 */
	private static String sendConverse(String str) {
		char[] cs = str.toCharArray();
		StringBuilder strs = new StringBuilder("");
		for (int i = 0; i < cs.length; i++) {
			if (Character.isUpperCase(cs[i])) {
				strs.append(String.valueOf("_" + cs[i]));
				continue;
			}
			strs.append(String.valueOf(cs[i]));
		}
		return strs.toString().toUpperCase();
	}

	/**
	 * 错误信息
	 * 
	 * @param str
	 * @return
	 */
	private static CompositeData returnError(String code, String msg) {
		CompositeData resp_data = new CompositeData();
		Map<String, Object> result = new HashMap<String, Object>();
		List<Map<String, Object>> retList = new ArrayList<Map<String, Object>>();
		Map<String, Object> sysHead = new HashMap<String, Object>();
		Map<String, Object> retMap = new HashMap<String, Object>();
		retMap.put("retCode", code);
		retMap.put("retMsg", msg);
		retList.add(retMap);
		sysHead.put("ret", retList);
		sysHead.put("retStatus", "F");
		result.put("sysHead", sysHead);
		resp_data = EsbConversionUtil.mapToCompositeData(result);
		return resp_data;
	}

//	public static void main(String[] args) {
//		
//
//		// ---------------
//		Map outputMap1 = new HashMap<String, Object>();
//		outputMap1.put("code", "success");
//		outputMap1.put("externalCode", null);
//		outputMap1.put("domain", null);
//		outputMap1.put("message", "success");
//		outputMap1.put("parameterList", null);
//		outputMap1.put("externalSystem", 11111);
//		outputMap1.put("externalMessage", null);
//		outputMap1.put("type", "S");
//		Map outputMap = new HashMap<String, Object>();
//
//		outputMap.put("returnCode", outputMap1);
//		outputMap.put("minRate", null);
//		outputMap.put("maxRate", null);
//		outputMap.put("responseMessage", "success");
//		outputMap.put("bosentSequence", "2018011900000000000001760099");
//		outputMap.put("intestArray", 3333333);
//		outputMap.put("minRate", null);
//		outputMap.put("minRate", null);
//		outputMap.put("minRate", null);
//		outputMap.put("minRate", null);
//		outputMap.put("minRate", null);
//
//		Map outputMap3 = new HashMap<String, Object>();
//		outputMap3.put("intRate", 5.04);
//		outputMap3.put("accrualScaleNo", "021");
//		outputMap3.put("accrualScaleName", "6：1");
//		outputMap3.put("rrPn", null);
//		outputMap3.put("overRate", 7.56);
//		outputMap3.put("accrualScalePct", 6);
//
//		Map outputMap4 = new HashMap<String, Object>();
//		outputMap4.put("intRate", 5.04);
//		outputMap4.put("accrualScaleNo", "021");
//		outputMap4.put("accrualScaleName", "6：1");
//		outputMap4.put("rrPn", null);
//		outputMap4.put("overRate", 0);
//		outputMap4.put("accrualScalePct", 6);
//
//		Map outputMap5 = new HashMap<String, Object>();
//		outputMap5.put("intRate", 5.04);
//		outputMap5.put("accrualScaleNo", "021");
//		outputMap5.put("accrualScaleName", "6：1");
//		outputMap5.put("rrPn", null);
//		outputMap5.put("overRate", 7.56);
//		outputMap5.put("accrualScalePct", 6);
//
//		Map outputMap6 = new HashMap<String, Object>();
//		outputMap6.put("intRate", 5.04);
//		outputMap6.put("accrualScaleNo", "021");
//		outputMap6.put("accrualScaleName", "6：1");
//		outputMap6.put("rrPn", null);
//		outputMap6.put("overRate", 7.56);
//		outputMap6.put("accrualScalePct", 6);
//
//		Map outputMap7 = new HashMap<String, Object>();
//		outputMap7.put("intRate", 5.04);
//		outputMap7.put("accrualScaleNo", "021");
//		outputMap7.put("accrualScaleName", "6：1");
//		outputMap7.put("rrPn", null);
//		outputMap7.put("overRate", 7.56);
//		outputMap7.put("accrualScalePct", 6);
//
//		Map outputMap8 = new HashMap<String, Object>();
//		outputMap8.put("intRate", 5.04);
//		outputMap8.put("accrualScaleNo", "021");
//		outputMap8.put("accrualScaleName", "6：1");
//		outputMap8.put("rrPn", null);
//		outputMap8.put("overRate", 7.56);
//		outputMap8.put("accrualScalePct", 6);
//
//		Map outputMap9 = new HashMap<String, Object>();
//		outputMap9.put("intRate", 5.04);
//		outputMap9.put("accrualScaleNo", "021");
//		outputMap9.put("accrualScaleName", "6：1");
//		outputMap9.put("rrPn", null);
//		outputMap9.put("overRate", 7.56);
//		outputMap9.put("accrualScalePct", 6);
//
//		Map outputMap10 = new HashMap<String, Object>();
//		outputMap10.put("intRate", 5.04);
//		outputMap10.put("accrualScaleNo", "021");
//		outputMap10.put("accrualScaleName", "6：1");
//		outputMap10.put("rrPn", null);
//		outputMap10.put("overRate", 7.56);
//		outputMap10.put("accrualScalePct", 6);
//
//		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
//		list.add(outputMap3);
//		list.add(outputMap4);
//		list.add(outputMap5);
//		list.add(outputMap6);
//		list.add(outputMap7);
//		list.add(outputMap8);
//		list.add(outputMap9);
//		list.add(outputMap10);
//
//		outputMap.put("intestArray", list);
//		CompositeData comm1 = EsbConversionUtil.mapToCompositeData(outputMap);
//		System.out.println(comm1);
//		String aaa = "23432";
//
//	}

}
